package com.h2cloud.Proxy._2_getProxyClass;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Package: com.h2cloud.Proxy.test
 * @ClassName: ProxyTest
 * @Author: h2cloud
 * @CreateTime: 2022/5/26 5:55 下午
 * @Description:
 */
interface Calculator {
	int add(int a, int b);
}

class CalculatorImpl implements Calculator {
	@Override
	public int add(int a, int b) {
		return a + b;
	}
}

public class ProxyTest_2 {
	public static void main(String[] args) throws Throwable {
		// 1.得到目标对象
		CalculatorImpl target = new CalculatorImpl();
		// 2.传入目标对象，得到增强对象（如果需要对目标对象进行别的增强，可以另外编写 getXxInvocationHandler）
		InvocationHandler logInvocationHandler = getLogInvocationHandler(target);
		// 3.传入接口+增强对象（含目标对象），得到代理对象
		Calculator calculatorProxy = (Calculator) getProxy(
				target.getClass().getClassLoader(),    // 随便传入一个类加载器
				target.getClass().getInterfaces(),     // 需要代理的接口
				logInvocationHandler                   // 增强对象（包含 目标对象 + 增强代码）
		);
		calculatorProxy.add(1, 2);
	}

	/**
	 * 传入接口+增强（已经包含了目标对象），获取代理对象
	 *
	 * @param classLoader
	 * @param interfaces
	 * @param handler
	 * @return
	 * @throws Exception
	 */
	private static Object getProxy(final ClassLoader classLoader, final Class<?>[] interfaces, final InvocationHandler handler) throws Exception {
		// 参数1：随便找个类加载器给它 参数2：需要代理的接口
		Class<?> proxyClazz = Proxy.getProxyClass(classLoader, interfaces);
		Constructor<?> constructor = proxyClazz.getConstructor(InvocationHandler.class);
		return constructor.newInstance(handler);
	}

	/**
	 * 日志增强代码
	 *
	 * @param target
	 * @return
	 */
	private static InvocationHandler getLogInvocationHandler(final CalculatorImpl target) {
		return new InvocationHandler() {
			@Override
			public Object invoke(Object proxy1, Method method, Object[] args) throws Throwable {
				System.out.println(method.getName() + "方法开始执行...");
				Object result = method.invoke(target, args);
				System.out.println(result);
				System.out.println(method.getName() + "方法执行结束...");
				return result;
			}
		};
	}
}
